package cn.steel.config;

import cn.steel.domain.entity.User;
import cn.steel.mapper.UserMapper;
import jakarta.servlet.RequestDispatcher;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

import javax.sql.DataSource;
import java.net.URL;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    final private DataSource dataSource;
    final private UserMapper userMapper;

    @Value("${COOKIE.VALIDITY:604800}")
    private Integer COOKIE_VALIDITY;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(auth -> auth
                        // 公开访问的路径
                        .requestMatchers("/**","/guestLogin","/login","/register","/checkUsername","/checkEmail", "/css/**", "/js/**", "/uploads/**", "/error", "/fonts/**").permitAll()
                        .requestMatchers("/buyer", "/buyer/product/**").permitAll() // 商品列表和详情公开
                        // 角色限制的路径
                        .requestMatchers("/buyer/**").hasAuthority("BUYER")
                        .requestMatchers("/manager/**").hasAuthority("ADMIN")
                        .requestMatchers("/supplier/**").hasAuthority("SUPPLIER")
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .usernameParameter("username")
                        .passwordParameter("password")
                        .successHandler(loginSuccessHandler())
                        .failureHandler(loginFailureHandler())
                        .permitAll()
                )
                .csrf(csrf -> csrf
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                )
                .rememberMe(remember -> remember
                        .userDetailsService(userDetailsService())
                        .tokenValiditySeconds(COOKIE_VALIDITY)
                        .tokenRepository(tokenRepository())
                )
                .logout(logout -> logout
                        .logoutUrl("/logout")
                        .logoutSuccessUrl("/login?logout")
                        .invalidateHttpSession(true)
                        .deleteCookies("JSESSIONID", "remember-me")
                )
                .exceptionHandling(exception -> exception
                        .accessDeniedHandler(accessDeniedHandler())
                );

        return http.build();
    }

    @Bean
    public JdbcTokenRepositoryImpl tokenRepository() {
        JdbcTokenRepositoryImpl jr = new JdbcTokenRepositoryImpl();
        jr.setDataSource(dataSource);
        return jr;
    }

    @Bean
    public AuthenticationManager authenticationManager(
            HttpSecurity http,
            BCryptPasswordEncoder bCryptPasswordEncoder
    ) throws Exception {
        AuthenticationManagerBuilder builder = http.getSharedObject(AuthenticationManagerBuilder.class);
        String userSQL = "select username, password, status from user where username = ?";
        String authoritySQL = "select username, role as authority from user where username = ?";
        builder.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(bCryptPasswordEncoder)
                .usersByUsernameQuery(userSQL)
                .authoritiesByUsernameQuery(authoritySQL);
        return builder.build();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        JdbcUserDetailsManager jdbcUserDetailsManager = new JdbcUserDetailsManager(dataSource);
        jdbcUserDetailsManager.setUsersByUsernameQuery("select username, password, status from user where username = ?");
        jdbcUserDetailsManager.setAuthoritiesByUsernameQuery("select username, role as authority from user where username = ?");
        return jdbcUserDetailsManager;
    }

    private AuthenticationSuccessHandler loginSuccessHandler() {
        return (request, response, authentication) -> {
            String username = authentication.getName();
            User user = userMapper.getUserByUsername(username);
            if (user != null) {
                request.getSession().setAttribute("user", user); // 将登录用户写入 session
            }

            // 重定向逻辑
            RequestCache requestCache = new HttpSessionRequestCache();
            SavedRequest savedRequest = requestCache.getRequest(request, response);
            if (savedRequest != null) {
                response.sendRedirect(savedRequest.getRedirectUrl());
            } else {
                // 根据角色重定向
                if (user.getRole().equals("SUPPLIER")) {
                    response.sendRedirect("/supplier/product");
                } else if (user.getRole().equals("BUYER")) {
                    response.sendRedirect("/buyer");
                } else if (user.getRole().equals("ADMIN")) {
                    response.sendRedirect("/manager/product");
                } else {
                    response.sendRedirect("/login?error=true");
                }
            }
        };
    }


    private AuthenticationFailureHandler loginFailureHandler() {
        return (request, response, exception) -> {
            String url = request.getParameter("url");
            response.sendRedirect("/login?error=true" + (url != null ? "&url=" + url : ""));
        };
    }

    private AccessDeniedHandler accessDeniedHandler() {
        return (request, response, exception) -> {
            response.sendRedirect("/error?accessDenied=true");
        };
    }
}